package com.webserver.http;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.HashMap;
import java.util.Map;

/**
 * 服务端解析请求类, 处理客户端发送过来的请求
 * <p>
 * 负责：
 * 1.解析请求行
 * 2.解析消息头
 * 3.解析消息正文
 * 4.提供方法来让其他类获取解析的内容
 */
public class HttpServletRequest {
    //声明一个Socket类型的变量, 用于保存传入的socket
    private Socket socket;
    //声明或创建变量, 用于保存请求中的各个属性
    private String method;
    private String url;
    private String protocol;
    private Map<String, String> headers = new HashMap<>();

    /**
     * HttpServletRequest类的有参构造
     * <p>
     * 负责：
     * 1.初始化所有成员变量
     * 2.解析请求行, 消息头, 与消息正文
     * @throws IOException 抛出来自void parseRequestLine(),
     * void parseHeaders(), void parseContent()三个方法的IO异常
     * @param socket 传入的应该与是客户端连接的socket
     */
    public HttpServletRequest (Socket socket) throws IOException {
        //将socket的值传递给本类的socket(this.socket)
        this.socket = socket;

        //调用void parseRequestLine()方法来解析请求行
        parseRequestLine();
        //调用void parseHeaders()方法来解析消息头
        parseHeaders();
        //调用void parseContent()方法来解析消息正文
        parseContent();

    }

    /**
     * void parseRequestLine()方法
     * <p>
     * 负责：解析请求行
     * @throws IOException 抛出来自String readLine()方法的IO异常
     */
    private void parseRequestLine() throws IOException {
        //获取请求行
        String line = readLine();
        //将请求行按" "符分隔
        String[] reqArr = line.split("\\s");
        //获取method属性
        method = reqArr[0];
        //获取url属性
        url = reqArr[1];
        //获取protocol属性
        protocol = reqArr[2];
    }

    /**
     * void parseHeaders()方法
     * <p>
     * 负责：解析消息头
     * @throws IOException 抛出来自String readLine()方法的IO异常
     */
    private void parseHeaders() throws IOException {
        //创建一个String类型的变量, 用于接收读取的内容
        String line;

        //当读取到内容时进入(消息头结尾会有一个空行, 读取时会返回空字符串即"")
        while (!(line = readLine()).isEmpty()){
            //将每一行按": "字符串来分隔
            String[] infoArr = line.split(": ");
            //将分隔好的内容以键值对的形式即(Key,Value)保存到headers中
            headers.put(infoArr[0],infoArr[1]);
        }
    }


    /**
     * void parseContent()方法
     * <p>
     * 负责：解析消息正文
     * @throws IOException 抛出来自String readLine()方法的IO异常
     */
    private void parseContent() throws IOException {
        //TODO---
    }

    /**
     * String readLine()方法
     * <p>
     * 负责：将请求中的一行字符串读取到并返回
     * @return 在请求中读取到的一行字符串
     * @throws IOException 抛出创建字节输入流时的异常
     */
    private String readLine() throws IOException {
        //创建连接客户端的字节输入流
        InputStream in = socket.getInputStream();
        //创建一个int类型变量d用于之后保存读出的数据
        int d = 0;
        //创建两个char类型变量用于之后保存连个相邻的字符
        char cur = 0, pre = 0;
        //创建一个StringBuilder类型的变量, 用于之后拼接字符串
        StringBuilder builder = new StringBuilder();

        //循环读取请求, 没读到末尾并且读到的连个相邻字符不是回车+换行时进入循环
        while(d != -1 && (pre != 13 || cur != 10)){
            //读取一个字节的数据
            d = in.read();
            //将cur的值赋给pre
            pre = cur;
            //将当前读取的数据赋给cur
            cur = (char)d;
            //将cur拼接到builder上
            builder.append(cur);
        }

        //将builder转成字符串再去掉两边空白字符后返回
        return builder.toString().trim();
    }

    /**
     * String getHeader()方法
     * <p>
     * 负责：返回传入参数在headers中对应的值
     * @param param 想要获取的值的参数名
     * @return 通过传入的参数找到的值
     */
    public String getHeader(String param) {
        return headers.get(param);
    }

    //成员实例的get方法, 负责让外面的类获取解析信息
    public String getMethod() {
        return method;
    }

    public String getUrl() {
        return url;
    }

    public String getProtocol() {
        return protocol;
    }
}
